package mysql

import (
	"go.uber.org/zap"
	"struggle/model"
)

type zanDAO struct{}

var DefaultZan = zanDAO{}

// Create 一个已登录用户给文章、提问、评论、回答点赞
func (z zanDAO) Create(zan *model.ZanMeta) (err error) {
	// 涉及处理多表，需要使用事务
	tx, err := db.Begin()
	if err != nil {
		zap.L().Error("mysql transaction failed", zap.Error(err))
		return
	}
	defer ClearTransaction(tx) // 如果出现异常情况,导致没有 commit和rollback,可以用来收尾

	// 1. 新增用户赞表数据
	sql1 := `INSERT IGNORE INTO st_zan (user_sn, objtype, objid) VALUES (?, ?, ?)`
	_, err = tx.Exec(sql1, zan.UserSn, zan.ObjectType, zan.ObjectId)
	if err != nil {
		zap.L().Error("zanDAO.Create failed", zap.Any("zan", zan), zap.Error(err))
		return
	}
	// 2. 统计指定类型指定ID的称赞数量 和 作者 称赞数量的更新
	if err = z.Update(zan); err != nil {
		zap.L().Error("zanDAO.Update failed", zap.Any("zan", zan), zap.Error(err))
		return
	}
	// 事务提交
	if err := tx.Commit(); err != nil {
		zap.L().Error("commit view failed", zap.Any("zan", zan), zap.Error(err))
	}
	return
}

// 统计指定类型指定ID的称赞数量 和 作者 称赞数量的更新
func (z zanDAO) Update(zan *model.ZanMeta) (err error) {
	// 1. 统计指定类型指定ID的称赞数量
	count, err := z.Get(zan.ObjectType, zan.ObjectId)
	var (
		author      uint64
		numArticle  int
		numQuestion int
		numAnswer   int
		numComment  int
	)
	// 2. 称赞类型 0-文章;1-问题;2-回答;3-评论
	switch zan.ObjectType {
	case 0:
		err = DefaultArticle.UpdateExZan(zan.ObjectId, count)
		author, err = DefaultArticle.GetAuthor(zan.ObjectId)
		numArticle, err = DefaultArticle.GetAuthorZan(author)
		if err != nil {
			return
		}
	case 1:
		err = DefaultQuestion.UpdateExZan(zan.ObjectId, count)
		author, err = DefaultQuestion.GetAuthor(zan.ObjectId)
		numQuestion, err = DefaultQuestion.GetAuthorZan(author)
		if err != nil {
			return
		}
	case 2:
		err = DefaultAnswer.UpdateExZan(zan.ObjectId, count)
		author, err = DefaultAnswer.GetAuthor(zan.ObjectId)
		numAnswer, err = DefaultAnswer.GetAuthorZan(author)
		if err != nil {
			return
		}
	case 3:
		err = DefaultComment.UpdateExZan(zan.ObjectId, count)
		author, err = DefaultComment.GetAuthor(zan.ObjectId)
		numComment, err = DefaultComment.GetAuthorZan(author)
		if err != nil {
			return
		}
	}
	// 3. 更新作者被称赞的数量
	// 统计该作者文章、提问、评论、回答中所有称赞数量的总和
	num := numArticle + numQuestion + numAnswer + numComment
	if err = DefaultUserCount.UpdateZan(author, num); err != nil {
		return
	}
	return
}

// Delete 一个已登录用户给文章、提问、评论、回答取消点赞
func (z zanDAO) Delete(zan *model.ZanMeta) (err error) {
	// 涉及处理多表，需要使用事务
	tx, err := db.Begin()
	if err != nil {
		zap.L().Error("mysql transaction failed", zap.Error(err))
		return
	}
	defer ClearTransaction(tx) // 如果出现异常情况,导致没有 commit和rollback,可以用来收尾

	// 1. 新增用户赞表数据
	sql1 := `DELETE FROM st_zan  WHERE user_sn=? AND objtype=? AND objid=?`
	_, err = tx.Exec(sql1, zan.UserSn, zan.ObjectType, zan.ObjectId)
	if err != nil {
		zap.L().Error("zanDAO.Delete failed", zap.Any("zan", zan), zap.Error(err))
		return
	}
	// 2. 统计指定类型指定ID的称赞数量 和 作者 称赞数量的更新
	if err = z.Update(zan); err != nil {
		zap.L().Error("zanDAO.Update failed", zap.Any("zan", zan), zap.Error(err))
		return
	}

	// 事务提交
	if err := tx.Commit(); err != nil {
		zap.L().Error("commit view failed", zap.Any("zan", zan), zap.Error(err))
	}
	return
}

// 查询该用户是否已经给该文章、提问、评论、回答点赞
func (z zanDAO) FindBool(zan *model.ZanMeta) (count int, err error) {
	sqlStr := `SELECT count(1) FROM st_zan WHERE user_sn=? AND objtype=? AND objid=?`
	err = db.Get(&count, sqlStr, zan.UserSn, zan.ObjectType, zan.ObjectId)
	if err != nil {
		zap.L().Error("Get User Zan Count failed", zap.Error(err))
		return
	}
	return
}

// 获取指定类型和指定ID的 用户 总数
func (z zanDAO) Get(objType int, objId uint64) (count int, err error) {
	sqlStr := `SELECT  count(user_sn) FROM st_zan WHERE objtype = ? AND objid = ?`
	err = db.Get(&count, sqlStr, objType, objId)
	if err != nil {
		zap.L().Error("Get Zan Count failed", zap.Error(err))
		return
	}
	return
}
